package at.technikum_wien.embsys.aat.PriscillaCore.component;

import java.util.List;

import at.technikum_wien.embsys.aat.PriscillaCore.enums.BinaryState;
import at.technikum_wien.embsys.aat.PriscillaCore.enums.EnoceanComponentType;
import at.technikum_wien.embsys.aat.PriscillaCore.enums.OccupancyState;
import at.technikum_wien.embsys.aat.PriscillaCore.telegram.Telegram;



/**
 * 
 * EEP_07_11_01 component class - controller status
 *
 * Illumination: 0-510lx
 * Illumination set point: 0-255
 * Dimming output level: 0-255
 * Other contacts and status bits (see EonOCean Equipment Profiles)
 * 
 * @author B. Aigner
 * 
 */
public class EEP_07_11_01 implements EnoceanComponent {
	
	Telegram telegram;
	List<?> eventListener;
	
	float illumination = -300;
	int illuminationSetPoint = -300;
	int dimmingOutputLevel = -300;
	boolean repeater;
	boolean powerRelayTimer;
	boolean daylightHarvesting;
	boolean dimming;
	BinaryState contact;
	boolean powerRelay;
	OccupancyState occupancy = OccupancyState.INITIAL_STATE;
	
	EnoceanComponentType enoceanComponentType = EnoceanComponentType.EEP_07_11_01;
	boolean telegramCreation = false;
	
	int illumination_temp;
	float illumination_max = 510;
	float illumination_min = 0;
	int illumination_value_max = 255;
	int illumination_value_min = 0;
	
	float multiplier;
	
	/**
	 * This constructor is used for received packets.
	 * It will parse the telegram and set the corresponding members.
	 * 
	 * @param telegram Received Telegram
	 * @param listener Event subscriber list
	 */
	public EEP_07_11_01(Telegram telegram, List<?> listener) {
		super();
		this.telegram = telegram;
		this.eventListener = listener;
		
		illumination_temp = telegram.getData3();
		illuminationSetPoint = telegram.getData2();
		
		dimmingOutputLevel = telegram.getData1();

		if(checkBit(telegram.getData0(), 7)) {
			repeater = true;
		} else {
			repeater = false;
		}
		
		if(checkBit(telegram.getData0(), 6)) {
			powerRelayTimer = true;
		} else {
			powerRelayTimer = false;
		}
		
		if(checkBit(telegram.getData0(), 5)) {
			daylightHarvesting = true;
		} else {
			daylightHarvesting = false;
		}
		
		if(checkBit(telegram.getData0(), 4)) {
			dimming = true;
		} else {
			dimming = false;
		}
		
		if(checkBit(telegram.getData0(), 2)) {
			contact = BinaryState.TRUE;
		} else {
			contact = BinaryState.FALSE;
		}
		
		if(checkBit(telegram.getData0(), 1)) {
			occupancy = OccupancyState.OCCUPIED;
		} else {
			occupancy = OccupancyState.UNOCCUPIED;
		}
		
		if(checkBit(telegram.getData0(), 0)) {
			powerRelay = true;
		} else {
			powerRelay = false;
		}

		multiplier = (illumination_max - illumination_min) / (illumination_value_max - illumination_value_min);

		if(multiplier >= 0) {
			this.illumination = multiplier * illumination_temp + illumination_max;
		} else {
			this.illumination = multiplier * illumination_temp + illumination_min;
		}
		fireFrame();
	}

	/**
	 * Fire all associated events
	 */
	void fireFrame() {
		//TODO: ControllerStatus Event
		/*Iterator listen = eventListener.iterator();
		final FrameEventFan frameEventFan = new FrameEventFan(this, telegram.getDeviceID(), this.fanspeed, this.fantype );
		while (listen.hasNext()) {
			((LinkListener) listen.next()).frameReceived_Fan(frameEventFan);
		}*/
	}

	/**
	 * Void constructor. It is used to create a new telegram for sending
	 */
	public EEP_07_11_01() {
		super();
		telegram = new Telegram();
		telegramCreation = true;
	}

	/**
	 * This constructor is used to create a telegram (the device id is given as parameter)
	 * @param deviceID Full device ID
	 */
	public EEP_07_11_01(String deviceID) {
		super();
		telegram = new Telegram();
		telegram.setDeviceID(deviceID);
		telegramCreation = true;
	}
	
	boolean checkBit(int value, int bitNr) {
		return (value & (1 << bitNr)) != 0;
	}
	
	int setBit(int value, int bitNr) {
		return value | (1<<bitNr);
	}
	
	int clrBit(int value, int bitNr) {
		return value & (~(1<<bitNr));
	}
	@Override
	public String getDeviceID() {
		return telegram.getDeviceID();
	}
	@Override
	public String getORG() {
		return telegram.getxORG();
	}
	@Override
	public EnoceanComponentType getType() {
		return enoceanComponentType;
	}

	@Override
	public void setDeviceID(String deviceID) {
		telegram.setDeviceID(deviceID);
	}

	/**
	 * Creates a new telegram from the component
	 * 
	 * This method creates a new telegram (if the component is initialized with
	 * a constructor without a telegram as parameter) or returns the saved telegram.
	 * The new telegram is built up from the members in this class (in this case different controller status bytes). 
	 * @return Created telegram
	 */
	public Telegram getTelegram() {
		if(telegramCreation == true) {
			multiplier = (illumination_max - illumination_min) / (illumination_value_max - illumination_value_min);
			if(multiplier < 0) {
				illumination_temp = (int)((this.illumination - illumination_max) / multiplier);
			} else {
				illumination_temp = (int)((this.illumination - illumination_min) / multiplier);
			}
			telegram.setData3(illumination_temp);
			
			
			telegram.setData2(illuminationSetPoint);
			telegram.setData1(dimmingOutputLevel);
			

			if(repeater == false) {
				telegram.setData0(clrBit(telegram.getData0(),7));
			} else {
				telegram.setData0(setBit(telegram.getData0(),7));
			}
			
			if(powerRelayTimer == false) {
				telegram.setData0(clrBit(telegram.getData0(),6));
			} else {
				telegram.setData0(setBit(telegram.getData0(),6));
			}
			
			if(daylightHarvesting == false) {
				telegram.setData0(clrBit(telegram.getData0(),5));
			} else {
				telegram.setData0(setBit(telegram.getData0(),5));
			}
			
			if(dimming == false) {
				telegram.setData0(clrBit(telegram.getData0(),4));
			} else {
				telegram.setData0(setBit(telegram.getData0(),4));
			}
			
			if(contact == BinaryState.FALSE) {
				telegram.setData0(clrBit(telegram.getData0(),2));
			} else {
				telegram.setData0(setBit(telegram.getData0(),2));
			}
			
			if(occupancy == OccupancyState.OFF) {
				telegram.setData0(clrBit(telegram.getData0(),1));
			} else {
				telegram.setData0(setBit(telegram.getData0(),1));
			}
			
			if(powerRelay == false) {
				telegram.setData0(clrBit(telegram.getData0(),0));
			} else {
				telegram.setData0(setBit(telegram.getData0(),0));
			}
		}
		return telegram;
	}

	public float getIllumination() {
		return illumination;
	}

	public OccupancyState getOccupancy() {
		return occupancy;
	}

	public int getIlluminationSetPoint() {
		return illuminationSetPoint;
	}

	public int getDimmingOutputLevel() {
		return dimmingOutputLevel;
	}

	public boolean isRepeater() {
		return repeater;
	}

	public boolean isPowerRelayTimer() {
		return powerRelayTimer;
	}

	public boolean isDaylightHarvesting() {
		return daylightHarvesting;
	}

	public boolean isDimming() {
		return dimming;
	}

	public BinaryState getContact() {
		return contact;
	}

	public boolean isPowerRelay() {
		return powerRelay;
	}

	public void setIllumination(float illumination) {
		if(illumination > illumination_max) return;
		if(illumination < illumination_min) return;
		this.illumination = illumination;
	}

	public void setIlluminationSetPoint(int illuminationSetPoint) {
		if(illuminationSetPoint > 255) return;
		if(illuminationSetPoint < 0) return;
		this.illuminationSetPoint = illuminationSetPoint;
	}

	public void setDimmingOutputLevel(int dimmingOutputLevel) {
		if(dimmingOutputLevel > 255) return;
		if(dimmingOutputLevel < 0) return;
		this.dimmingOutputLevel = dimmingOutputLevel;
	}

	public void setRepeater(boolean repeater) {
		this.repeater = repeater;
	}

	public void setPowerRelayTimer(boolean powerRelayTimer) {
		this.powerRelayTimer = powerRelayTimer;
	}

	public void setDaylightHarvesting(boolean daylightHarvesting) {
		this.daylightHarvesting = daylightHarvesting;
	}

	public void setDimming(boolean dimming) {
		this.dimming = dimming;
	}

	public void setContact(BinaryState contact) {
		this.contact = contact;
	}

	public void setPowerRelay(boolean powerRelay) {
		this.powerRelay = powerRelay;
	}

	public void setOccupancy(OccupancyState occupancy) {
		this.occupancy = occupancy;
	}
}
